//-----------------------------------------------------------------------------
// Name: Input.cpp
// Auth: Bradford J. Smith & Robert Darty
// Desc: contains all call back functions related to keyboard handling
//-----------------------------------------------------------------------------

#include "Input.h"
#include "InputManager.h"
#include "Assert.h"
#include "DisplayManager.h"
#include "RobTown.h"
#include "SharedConstants.h"
#include "Systems.h"

#include <GL/glut.h>
#include <GL/freeglut_ext.h>

//-----------------------------------------------------------------------------
// Function Definitions:
//-----------------------------------------------------------------------------
void KeyDownFunction(GLubyte key, GLint x, GLint y)
{
	GetInputManager()->HandleKeyDown(key, x, y);

	cDisplayManager* pDisplayManager = GetDisplayManager();
	

	switch(key) 
	{
	// 1 Switches to full screen
	case '1':
		{
			glutFullScreen();
		}
		break;
	//2 Switches to windowed mode
	case '2':
		{
			//TODO: Ask Brad why double call is needed???
			glutReshapeWindow(kInitialWindowWidth, kInitialWindowHeight);
			glutPositionWindow(0, 0);
			glutReshapeWindow(kInitialWindowWidth, kInitialWindowHeight);
			glutPositionWindow(0, 0);
		}
		break;
	//w key down moves forwards
	case 'w':
		{
			pDisplayManager->Move(kStartMoveForward);
		}
		break;
	//s key down moves backwards
	case 's':
		{
			pDisplayManager->Move(kStartMoveBackward);
		}
		break;
	//a key down moves left
	case 'a':
		{
			pDisplayManager->Move(kStartMoveLeft);
		}
		break;
	//d key down moves right
	case 'd':
		{
			pDisplayManager->Move(kStartMoveRight);
		}
		break;
	//q quits!
	case 'q':
		glutLeaveMainLoop();
	}
	// Refresh the Window
	glutPostRedisplay();
}

//-----------------------------------------------------------------------------
void KeyUpFunction(GLubyte key, GLint x, GLint y)
{
	GetInputManager()->HandleKeyUp(key, x, y);
	cDisplayManager* pDisplayManager = GetDisplayManager();
	switch(key) 
	{
	// w key up stops forward movement
	case 'w':
		{
			pDisplayManager->Move(kStopMoveForward);
		}
		break;
	// s key up stops backward movement
	case 's':
		{
			pDisplayManager->Move(kStopMoveBackward);
		}
		break;
	// a key up stops strafe left
	case 'a':
		{
			pDisplayManager->Move(kStopMoveLeft);
		}
		break;
	// d key up stops strafe right
	case 'd':
		{
			pDisplayManager->Move(kStopMoveRight);
		}
		break;
	}
	// Refresh the Window
	glutPostRedisplay();
}


void SpecialKeyDownFunction(GLint key, GLint x, GLint y)
{
	GetInputManager()->HandleKeyDownSpecial(key, x, y);

	cDisplayManager* pDisplayManager = GetDisplayManager();
	//Left, right up and down do the same as WSAD
	switch (key)
	{
	case GLUT_KEY_LEFT:
		pDisplayManager->Move(kStartMoveLeft);
		break;
	case GLUT_KEY_RIGHT:
		pDisplayManager->Move(kStartMoveRight);
		break;
	case GLUT_KEY_UP:
		pDisplayManager->Move(kStartMoveForward);
		break;
	case GLUT_KEY_DOWN:
		pDisplayManager->Move(kStartMoveBackward);
		break;
	};

	// Refresh the Window
	glutPostRedisplay();
}

//-----------------------------------------------------------------------------
void SpecialKeyUpFunction(GLint key, GLint x, GLint y)
{
	GetInputManager()->HandleKeyUpSpecial(key, x, y);

	cDisplayManager* pDisplayManager = GetDisplayManager();;
	//Left, right up and down do the same as WSAD
	switch (key)
	{
	case GLUT_KEY_LEFT:
		pDisplayManager->Move(kStopMoveLeft);
		break;
	case GLUT_KEY_RIGHT:
		pDisplayManager->Move(kStopMoveRight);
		break;
	case GLUT_KEY_UP:
		pDisplayManager->Move(kStopMoveForward);
		break;
	case GLUT_KEY_DOWN:
		pDisplayManager->Move(kStopMoveBackward);
		break;
	};

	// Refresh the Window
	glutPostRedisplay();
}

//-----------------------------------------------------------------------------
void MouseMoveFunction(GLint x, GLint y)
{
	// get the old mouse coordinates before we update the input state.
	cInputManager* pInputManager = GetInputManager();
	int oldMouseX, oldMouseY;
	pInputManager->GetMousePosition(oldMouseX, oldMouseY);

	// update the input state.
	pInputManager->HandleMouseMove(x, y);

	//if (pInputManager->GetInputState(kMouseButtonRight) == kInputStateDown)
	//{
	//Set Cursor to invisible!
	glutSetCursor(GLUT_CURSOR_NONE);

	// read the current values:
	cDisplayManager* pDisplayManager = GetDisplayManager();
	float heading = pDisplayManager->GetCameraHeading();
	float pitch = pDisplayManager->GetCameraPitch();

	// determine the new heading based on the mouse's movement in x this frame.
	heading -= 0.7f * (float)(x - oldMouseX);
	pDisplayManager->SetCameraHeading(heading);

	// determine the new pitch based on the mouse's movement in y this frame.
	pitch -= 0.7f * (float)(y - oldMouseY);
	pDisplayManager->SetCameraPitch(pitch);

	//If the Mouse gets out of range in the X direction - reset it back to the middle
	//Handle the mouse move or the whole thing jerks back to its starting position rather
	//than continuing to rotate
	if (oldMouseX>pDisplayManager->GetWindowWidth()-50 || oldMouseX<50 )
	{
		glutWarpPointer(pDisplayManager->GetWindowWidth()/2, oldMouseY);
		pInputManager->HandleMouseMove(pDisplayManager->GetWindowWidth()/2, y);
	}
	//Like the above, except for Y direction
	if (oldMouseY>pDisplayManager->GetWindowHeight()-50 || oldMouseY<50)
	{
		glutWarpPointer(oldMouseX, pDisplayManager->GetWindowHeight()/2);
		pInputManager->HandleMouseMove(x, pDisplayManager->GetWindowHeight()/2);
	}
	/*}*/
}

//-----------------------------------------------------------------------------
void MouseClickFunc(GLint button, GLint state, GLint x, GLint y)
{
	cInputManager* pInputManager = GetInputManager();
	pInputManager->HandleMouseButton(button, state, x, y);
	//Doesnt do a whole lot of much until firing is in effect (jumping?)


	// handle mouse clicks
	//if (state == GLUT_DOWN)
	//{
	//	switch (button)
	//	{
	//	case GLUT_LEFT_BUTTON:
	//		// draw a debug pick line
	//		pInputManager->SetDebugPickLine();
	//		break;
	//	}
	//}

}
